﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Tomahawk.Runtime.Rendering;
using Tomahawk.Runtime.Input;

namespace Tomahawk.Runtime.Components
{
    public class FreeCamParameters : OverlayParameters
    {
        [XmlAttribute("MovementSpeed")]
        public float movementSpeed = 1.0f;

        [XmlAttribute("RotationSpeed")]
        public float rotationSpeed = 1.0f;
    }

    /// <summary>
    /// A reusable component for controlling the game camera for debug purposes
    /// </summary>
    public class FreeCamComponent : OverlayComponent
    {
        #region Instance
        private static FreeCamComponent instance = null;
        public static FreeCamComponent Instance { get { return instance; } }
        #endregion

        #region Fields
        public const string label = "FreeCamComponent";

        private Camera camera = new Camera();
        public Camera Camera { get { return camera; } }

        private float movementSpeed = 1.0f;
        public float MovementSpeed { get { return movementSpeed; } set { movementSpeed = value; } }

        private float rotationSpeed = 1.0f;
        public float RotationSpeed { get { return rotationSpeed; } set { rotationSpeed = value; } }

        public bool Activated
        {
            get
            {
                return Engine.Instance.CameraManager.ActiveCamera == Camera;
            }

            set
            {
                if (!Enabled)
                {
                    Engine.Instance.CameraManager.SetActiveCamera(label);
                }
            }
        }
        #endregion

        #region Initialization
        public static void Register(Game game, ref FreeCamParameters parameters)
        {
            if (parameters.enabled)
            {
                Vector2 basePos = Vector2.Zero;
                basePos.X = parameters.X;
                basePos.Y = parameters.Y;
                instance = new FreeCamComponent(basePos, game);

                instance.movementSpeed = parameters.movementSpeed;
                instance.rotationSpeed = parameters.rotationSpeed;

                game.Components.Add(instance);
            }
        }

        protected FreeCamComponent(Vector2 basePos, Game game)
            : base(basePos, game)
        {
            Engine.Instance.CameraManager.AddCamera(this.camera, label);
        }
        #endregion

        #region Update
        protected override void OnUpdate(GameTime gameTime)
        {
            float elapsedTime = (float) gameTime.ElapsedGameTime.TotalSeconds;

            if (Enabled)
            {
                #region Update Position
                Vector3 deltaMovement = Vector3.Zero;

                bool shiftPressed = Engine.Instance.InputManager.GetKeyboardIsDown(Keys.LeftShift) ||
                    Engine.Instance.InputManager.GetKeyboardIsDown(Keys.RightShift);

                float speedMultiplier = shiftPressed ? 5.0f : 1.0f;

                if (Engine.Instance.InputManager.GetKeyboardIsDown(Keys.W) ||
                    Engine.Instance.InputManager.GetKeyboardIsDown(Keys.Up))
                {
                    deltaMovement -= elapsedTime * movementSpeed * speedMultiplier * Camera.ZAxis;
                }
                if (Engine.Instance.InputManager.GetKeyboardIsDown(Keys.S) ||
                    Engine.Instance.InputManager.GetKeyboardIsDown(Keys.Down))
                {
                    deltaMovement += elapsedTime * movementSpeed * speedMultiplier * Camera.ZAxis;
                }
                if (Engine.Instance.InputManager.GetKeyboardIsDown(Keys.A) ||
                    Engine.Instance.InputManager.GetKeyboardIsDown(Keys.Left))
                {
                    deltaMovement -= elapsedTime * movementSpeed * speedMultiplier * Camera.XAxis;
                }
                if (Engine.Instance.InputManager.GetKeyboardIsDown(Keys.D) ||
                    Engine.Instance.InputManager.GetKeyboardIsDown(Keys.Right))
                {
                    deltaMovement += elapsedTime * movementSpeed * speedMultiplier * Camera.XAxis;
                }

                camera.EyePosition += deltaMovement;
                #endregion

                #region Update Rotation
                if (Engine.Instance.InputManager.GetMouseButtonState(InputManager.THMouseButtons.Left) == ButtonState.Pressed)
                {
                    Vector2 deltaCursor = Engine.Instance.InputManager.GetMouseCursorDisplacement();
                    Vector2 deltaRotation = -elapsedTime * movementSpeed * deltaCursor;

                    camera.Rotate(deltaRotation.X, deltaRotation.Y);
                }
                #endregion
            }
        }
        #endregion

        #region Draw
        protected override void OnDraw2D(GameTime gameTime)
        {
            string eyePos = string.Format("Eye position: {0}", camera.EyePosition);
            string viewDir = string.Format("View direction: {0}", camera.ViewVector);

            Color textColor = Color.White;
            DrawString(0, 0, "--------------------- CAMERA -------------------", ref textColor);
            DrawString(0, 10, eyePos, ref textColor);
            DrawString(0, 20, viewDir, ref textColor);
        }

        protected override void OnDraw3D(GameTime gameTime)
        {
            DrawGrid(Matrix.Identity, 250.0f, 20);
        }

        #endregion
    }
}
